package main

import (
	"fmt"
	"math"
	"sort"
)

// 异常处理
func ExceptionHandle() {
	fmt.Println("\n··········································开始捕获异常···········································")
	err := recover()
	if err != nil {
		fmt.Printf("\n~~~~%T~~~~%#[1]v``````````````````````\n", err)
	} else {
		fmt.Println("@@@@@@@@@@@有惊无险！##########")
	}
	fmt.Println("\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!异常处理结束!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
	fmt.Println()
}

// 1、实现对圆形、三角形、长方形求面积。
type AcreageCalculator interface {
	Acreage()
}

// 通用计算面积公式 多态
func Calculate(shape AcreageCalculator) {
	shape.Acreage()
}

type Shape struct {
	Name      string
	Perimeter float64 //周长
	arrea     float64 //面积
}

// 构造方法
func NewShape(name string, perimeter, acreage float64) *Shape {
	return &Shape{Name: name, Perimeter: perimeter, arrea: acreage}
}

type Round struct {
	Shape            // 半径 radius==Perimeter/2π
	diameter float64 //直径
}

func NewRound(s Shape, d float64) *Round {
	return &Round{s, d}
}

// Round's Acreage=πr²
func (r *Round) Acreage() {
	r.Shape.arrea = math.Pi * math.Pow(r.diameter/2, 2) // Acreage=(perimeter/2)*radius
}

type Triangle struct {
	Shape
	a, b, c float64 //三条边
}

// 构造三角形
func NewTriangle(s Shape, a, b, c float64) *Triangle {
	return &Triangle{s, a, b, c}
}

// Triangle's S=√p(p-a)(p-b)(p-c) 海伦公式
func (t *Triangle) Acreage() {
	if t.a+t.b <= t.c || t.a+t.c <= t.b || t.b+t.c <= t.a {
		defer ExceptionHandle()
		panic("三角形两条边之和必须大于第三边，否则无法构成三角形！")
	}
	if t.a+t.b+t.c != t.Perimeter {
		defer ExceptionHandle()
		panic("传参有误，三条边之和不等于周长,计算面积为0！")
	}
	p := t.Perimeter / 2
	r := p * (p - t.a) * (p - t.b) * (p - t.c)
	t.Shape.arrea = math.Sqrt(r)
}

type Square struct {
	Shape
	Edge float64
}

func NewSquare(s Shape, e float64) *Square {
	return &Square{s, e}
}

// Square's Acreage=side*side
func (s *Square) Acreage() {
	if s.Perimeter/4 != s.Edge {
		defer ExceptionHandle()
		panic("正方形周长必须是每条边的四倍！")
	}
	s.Shape.arrea = math.Pow(s.Edge, 2)
}

type Rectangle struct {
	Shape
	Floor float64
}

// Rectangle's Acreage=(perimeter/2-floor)*floor
func (t *Rectangle) Acreage() {
	if t.Floor >= t.Perimeter/2 {
		defer ExceptionHandle()
		panic("矩形边长必须小于周长的一半！")
	}
	t.Shape.arrea = t.Floor * (t.Perimeter/2 - t.Floor)
}

// 2、利用第1题，构造3个以上图形，至少圆形、三角形、矩形各有一个，对上题的图形按照面积降序排列
type ShapeSlice []Entry

func (a ShapeSlice) Len() int           { return len(a) }
func (a ShapeSlice) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ShapeSlice) Less(i, j int) bool { return a[i].Value.arrea < a[j].Value.arrea } //<是升序 >是降序
// 引入泛型
type MyMap[K int, V Shape] map[K]V
type Entry struct {
	Key   int
	Value Shape
}

func main() {
	// 圆形实例
	circle := NewRound(*NewShape("圆形", 36, 0), 36/math.Pi)
	Calculate(circle) //计算面积
	fmt.Printf("%T %+[1]v\n", circle)
	fmt.Println("——————————————————————————————————————————下面打印三角形对象————————————————————————————————————————————————————————")
	// 三角形实例化
	triangle := NewTriangle(*NewShape("正三角形1", 36, 0), 12, 12, 12)
	Calculate(triangle)
	fmt.Printf("%T %+[1]v\n", triangle)
	t2 := NewTriangle(*NewShape("锐角三角形2", 36, 0), 11, 12, 13)
	Calculate(t2)
	fmt.Printf("%T %+[1]v\n", t2)
	t3 := NewTriangle(*NewShape("面积是0,无法构成三角形", 36, 0), 12, 13, 14)
	Calculate(t3)
	fmt.Printf("%T %+[1]v\n", t3)
	fmt.Println("---------------------------------------------------------------------------------------")
	//实例化正方形
	square := NewSquare(*NewShape("正方形", 36, 0), 9)
	Calculate(square)
	fmt.Printf("%T %+[1]v\n", square)
	fmt.Println("===========================================下面打印矩形对象==========================================================")
	//矩形实例化
	rectangle := &Rectangle{*NewShape("长矩形1", 36, 0), 17}
	Calculate(rectangle)
	fmt.Printf("%T %+[1]v\n", rectangle)
	r2 := &Rectangle{*NewShape("宽矩形2", 36, 0), 10}
	Calculate(r2)
	fmt.Printf("%T %+[1]v\n", r2)
	fmt.Println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~下面对相同周长的形状按面积排序~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
	//开始排序
	var m = MyMap[int, Shape]{0: circle.Shape, 1: triangle.Shape, 2: t2.Shape, 3: square.Shape, 4: rectangle.Shape, 5: r2.Shape, 6: t3.Shape}
	// fmt.Printf("%T==> %#[1]v\n", m)
	n := make([]Entry, len(m))
	o := 0
	for k, v := range m {
		n[o] = Entry{k, v}
		o++
	}
	fmt.Printf("%T==> %+[1]v\n", n)
	sort.Slice(n, func(i, j int) bool { return n[i].Value.arrea > n[j].Value.arrea }) //按面积降序排序
	fmt.Println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
	// sort.Sort(ShapeSlice(n)) //升序
	fmt.Println(n)
}
